using System.Diagnostics;

namespace FluentParser.Expressions.Rules.Composition
{
    /// <summary>
    /// Similar to choice rule but with the opposite behavior. Instead of
    /// using the second expression on failure, it uses the second expression
    /// only on success.
    /// </summary>
    /// <typeparam name="TSource">Type of the source tokens</typeparam>
    /// <example><code>
    /// var badName = ParseString.Regex("_[A-Za-z]*");
    /// var warning = Errors.Warning("Name should not start with an underscore");
    /// var badNameAndWarning = parseName &amp; warning;
    ///  
    /// badName.Parse("_NameWithUnderscore")           --> "_NameWithUnderscore"
    /// badName.Parse("SomeOtherName")                 --> failure
    /// badNameAndWarning.Parse("_NameWithUnderscore") --> "_NameWithUnderscore" &amp; Warning
    /// badNameAndWarning.Parse("SomeOtherName")       --> failure
    /// </code></example>
    [DebuggerDisplay("[GreedyChoiceExpressionRule {Left.GetType().Name} & {Right.GetType().Name}]")]
    public class GreedyChoiceExpressionRule<TSource> : Expr<TSource>
    {
        public Expr<TSource> Left { get; private set; }
        public Expr<TSource> Right { get; private set; }

        public GreedyChoiceExpressionRule(Expr<TSource> left, Expr<TSource> right)
        {
            Left = left;
            Right = right;
            TypeOperation = OperationType.Combination;
        }

        public override ParsingResult<TSource> Parse(GrammarContext context, int index)
        {
            ParsingResult<TSource> leftResult = Left.Parse(context, index);
            if (leftResult != null)
            {
                ParsingResult<TSource> rightResult = Right.Parse(context, index);
                if (rightResult != null)
                    return rightResult;
            }

            return leftResult;
        }

        public override void ParseNode(GrammarContext context, ParsingNodeResult node)
        {
            ParsingNodeResult leftResult = node.AddChild(Left, context);
            if (leftResult.IsSuccess)
            {
                ParsingNodeResult rightResult = node.AddChild(Right, context);
                node.Value = rightResult.IsSuccess ? rightResult.Value : leftResult.Value;
                node.IsSuccess = true;
            }
        }
    }
}